use crate::dto;
use crate::service::Error;
use crate::service::network_acl::NetworkAclService;
use crate::service::network_acl_rule::NetworkAclRuleService;
use std::sync::Arc;

#[async_trait::async_trait]
pub trait NetworkAclManagerService: NetworkAclService {
    async fn get_info(
        &self,
        network_acl_id: &str,
    ) -> Result<dto::network_acl::NetworkAclInfo, Error>;
}

pub struct DefaultNetworkAclManagerService {
    network_acl_service: Arc<dyn NetworkAclService>,
    network_acl_rule_service: Arc<dyn NetworkAclRuleService>,
}

impl DefaultNetworkAclManagerService {
    pub fn new(
        network_acl_service: Arc<dyn NetworkAclService>,
        network_acl_rule_service: Arc<dyn NetworkAclRuleService>,
    ) -> Self {
        Self {
            network_acl_service,
            network_acl_rule_service,
        }
    }
}

#[async_trait::async_trait]
impl NetworkAclService for DefaultNetworkAclManagerService {
    async fn add(
        &self,
        params: &dto::core::network_acl::AddParams,
    ) -> Result<dto::core::network_acl::AddResponseData, Error> {
        self.network_acl_service.add(params).await
    }

    async fn get(
        &self,
        network_acl_id: &str,
    ) -> Result<dto::core::network_acl::NetworkAclItem, Error> {
        self.network_acl_service.get(network_acl_id).await
    }

    async fn try_get(
        &self,
        network_acl_id: &str,
    ) -> Result<Option<dto::core::network_acl::NetworkAclItem>, Error> {
        self.network_acl_service.try_get(network_acl_id).await
    }

    async fn list(
        &self,
        filter: &dto::core::network_acl::Filter,
        offset: u64,
        limit: u64,
    ) -> Result<Vec<dto::core::network_acl::NetworkAclItem>, Error> {
        self.network_acl_service.list(filter, offset, limit).await
    }

    async fn update(
        &self,
        network_acl_id: &str,
        params: &dto::core::network_acl::UpdateParams,
    ) -> Result<(), Error> {
        self.network_acl_service
            .update(network_acl_id, params)
            .await
    }

    async fn delete(&self, network_acl_id: &str) -> Result<(), Error> {
        self.network_acl_rule_service
            .delete_by_network_acl_id(network_acl_id)
            .await?;
        self.network_acl_service.delete(network_acl_id).await
    }

    async fn count(&self, filter: &dto::core::network_acl::Filter) -> Result<u64, Error> {
        self.network_acl_service.count(filter).await
    }
}

#[async_trait::async_trait]
impl NetworkAclManagerService for DefaultNetworkAclManagerService {
    async fn get_info(
        &self,
        network_acl_id: &str,
    ) -> Result<dto::network_acl::NetworkAclInfo, Error> {
        let item = self.get(network_acl_id).await?;

        let ingress_rules = self
            .network_acl_rule_service
            .all_ingress_rules(network_acl_id)
            .await?;

        let egress_rules = self
            .network_acl_rule_service
            .all_egress_rules(network_acl_id)
            .await?;

        Ok(dto::network_acl::NetworkAclInfo {
            inner: item,
            ingress_rules,
            egress_rules,
        })
    }
}
